﻿using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.OpenApi.Models;
using My.Core.Options;
using My.Framework.AspNetCore;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Reflection;
using Swashbuckle.AspNetCore.Filters;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using My.Core.Swagger.Filters;
using My.Framework;
using My.Core.Util;
using AspNetCoreRateLimit;

namespace My.Core.Swagger
{
    public class SwaggerStartup : StartupModule<SwaggerStartup>
    {
        /// <summary>
        /// 程序启动器
        /// </summary>
        public SwaggerStartup() => Order = 1;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="webApplicationBuilder"></param>
        public override void ConfigureServices(WebApplicationBuilder webApplicationBuilder)
        {
            var services = webApplicationBuilder.Services;

			// 读swagger配置
			var swaggerSetting = App.GetConfig<SwaggerSetting>("swaggerSetting");

            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc(swaggerSetting.Version, new OpenApiInfo
                {
                    Title = swaggerSetting.Title,
                    Version = swaggerSetting.Version,
                    Description = swaggerSetting.Description,
                });

                // TODO:一定要返回true！
                c.DocInclusionPredicate((docName, description) => true);

                string FileDirectory = AppDomain.CurrentDomain.BaseDirectory;   // 获取基目录

                //IncludeXmlComments(c, FileDirectory, AppDomain.CurrentDomain.FriendlyName + ".xml"); // 增加当前工程swagger文档

                //var assembly = AssemblyUtils.GetAssemblies().ToList();
                //foreach (var an in assembly)
                //{


                //	if (!an.GetName().Name.Contains("System") &&
                //		!an.GetName().Name.Contains("mscorlib") && !an.GetName().Name.Contains("Microsoft"))
                //	{
                //		IncludeXmlComments(c, FileDirectory, an.GetName().Name + ".xml");
                //	}
                //}

                // 添加引用的所有程序集swagger文档
                //Assembly assem = Assembly.GetEntryAssembly();
                //foreach (AssemblyName an in assem.GetReferencedAssemblies())
                //{
                //    if (!an.Name.Contains("System") &&
                //        !an.Name.Contains("mscorlib") && !an.Name.Contains("Microsoft"))
                //    {
                //        IncludeXmlComments(c, FileDirectory, an.Name + ".xml");
                //    }
                //}

    //            var assemblyList = App.Startups.Select(w => w.GetType().Assembly).ToList();
    //            foreach (var item in assemblyList)
    //            {
				//	IncludeXmlComments(c, FileDirectory, item.GetName().Name + ".xml");
				//}

                var assemblyList = AssemblyUtil.GetAssemblyList().Where(w => !w.IsDynamic).ToList();
				foreach (var item in assemblyList)
				{
					IncludeXmlComments(c, FileDirectory, item.GetName().Name + ".xml");
				}

				//参考文章：http://www.zyiz.net/tech/detail-134965.html
				//需要安装包Swashbuckle.AspNetCore.Filters
				// 开启权限小锁 需要在对应的Action上添加[Authorize]才能看到
				c.OperationFilter<AddResponseHeadersFilter>();
                c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();
                //在header 中添加token，传递到后台
                c.OperationFilter<SecurityRequirementsOperationFilter>();
                c.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme,
                    new OpenApiSecurityScheme
                    {
                        In = ParameterLocation.Header,
                        Description = "请输入Login接口返回的Token，前置Bearer。示例：Bearer {Token}",
                        Name = "Authorization",//jwt默认的参数名称,
                        Type = SecuritySchemeType.ApiKey, //指定ApiKey
                        BearerFormat = "JWT",//标识承载令牌的格式 该信息主要是出于文档目的
                        Scheme = JwtBearerDefaults.AuthenticationScheme//授权中要使用的HTTP授权方案的名称
                    });
                c.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }
                        },
                        new List<string>()
                    }
                });

                c.OperationFilter<AuthenticationOperationFilter>();
			});

			// 配置MiniProfiler服务
			services.AddMiniProfiler(options => {
				//这里是配置了MiniProfiler的路由基础路径，默认的路径是/mini-profiler-resources
				//按照当前配置，你可以使用"/profiler/results"来访问分析报告
				options.RouteBasePath = "/profiler";
			});
		}

        /// <summary>
        /// 
        /// </summary>
        /// <param name="webApplication"></param>
        public override void Configure(WebApplication webApplication)
        {
			// 读swagger配置
			var swaggerSetting = App.GetConfig<SwaggerSetting>("swaggerSetting");

            // Configure the HTTP request pipeline.
            if (webApplication.Environment.IsDevelopment())
            {
                webApplication.UseSwagger(c =>
                {
                    //c.PreSerializeFilters.Add((swaggerDoc, httpReq) => { ApiRusltFilter.ApiRuslt(swaggerDoc, httpReq); });
                });

                webApplication.UseSwaggerUI(c =>
                {
                    var customIndex = $"{Assembly.GetExecutingAssembly().GetName().Name}.html.index.html";
                    c.IndexStream = (Func<Stream>)(() => Assembly.GetExecutingAssembly().GetManifestResourceStream(customIndex));
                    c.RoutePrefix = "swagger";
                    c.SwaggerEndpoint("/swagger/v1/swagger.json", swaggerSetting.Title + " " + swaggerSetting.Version);
                });
            }

			// 激活MiniProfiler中间件，启用MiniProfiler服务，放在UseEndpoints方法之前。
			webApplication.UseMiniProfiler();
		}

        /// <summary>
        /// 加载指定swagger文档
        /// </summary>
        /// <param name="c"></param>
        /// <param name="FileDirectory">文件目录</param>
        /// <param name="Name">文件名</param>
        private void IncludeXmlComments(SwaggerGenOptions c, string FileDirectory, string Name)
        {
            try
            {
                c.IncludeXmlComments(Path.Combine(FileDirectory, Name), true); // 增加swagger文档
				Console.WriteLine("swagger 文档加载:" + Name);
			}
            catch (Exception ex)
            {
                Console.WriteLine("swagger 文档加载失败" + ex.Message);
            }
        }
    }
}
